home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / proplist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-01  |  9.2 KB  |  492 lines

  1. /* proplist.c- Hand made proplist parser.
  2.  *     The one in libPropList causes wmaker to crash if an error is found in
  3.  * the parsed file. This parser is also more rigid: it will not accept any
  4.  * property lists with errors, but will print more descriptive error messages
  5.  * and will hopefully not crash.
  6.  *
  7.  *  Window Maker window manager
  8.  * 
  9.  *  Copyright (c) 1998 Alfredo K. Kojima
  10.  * 
  11.  *  This program is free software; you can redistribute it and/or modify
  12.  *  it under the terms of the GNU General Public License as published by
  13.  *  the Free Software Foundation; either version 2 of the License, or
  14.  *  (at your option) any later version.
  15.  *
  16.  *  This program is distributed in the hope that it will be useful,
  17.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  *  GNU General Public License for more details.
  20.  *
  21.  *  You should have received a copy of the GNU General Public License
  22.  *  along with this program; if not, write to the Free Software
  23.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  24.  *  USA.
  25.  */
  26.  
  27. #include "wconfig.h"
  28. #include "WindowMaker.h"
  29.  
  30. #include <proplist.h>
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <ctype.h>
  35.  
  36.  
  37. #if 0
  38. #define DPUT(s)     puts(s)
  39. #else
  40. #define DPUT(s)
  41. #endif
  42.  
  43.  
  44. #define INITIAL_BUFFER_SIZE    (16*1024)
  45.  
  46. #define BUFFER_SIZE_INCREMENT    1024
  47.  
  48.  
  49. static int line_number = 1;
  50. static int buffer_size = 0;
  51. static char *buffer = NULL;
  52. static char *file_name;
  53.  
  54.  
  55. static proplist_t get_object(FILE *f);
  56. static proplist_t get_array(FILE *f);
  57. static proplist_t get_string(FILE *f);
  58. static proplist_t get_qstring(FILE *f);
  59. static proplist_t get_dictionary(FILE *f);
  60.  
  61.  
  62. static INLINE int
  63. get_char(FILE *f)
  64. {
  65.     int c;
  66.     
  67.     c = fgetc(f);
  68.     if (c=='\n')
  69.     line_number++;
  70.     return c;
  71. }
  72.  
  73.  
  74.  
  75. static INLINE int
  76. get_non_space_char(FILE *f)
  77. {
  78.     int c;
  79.     
  80.     while (1) {
  81.     c = fgetc(f);
  82.     if (c=='\n')
  83.         line_number++;
  84.     else if (!isspace(c))
  85.         break;
  86.     }
  87.  
  88.     if (c!=EOF) {
  89.     return c;
  90.     } else {
  91.     return EOF;
  92.     }
  93. }
  94.  
  95.  
  96. static char *
  97. unescapestr(char *src)
  98. {
  99.   char *dest = wmalloc(strlen(src)+1);
  100.   char *src_ptr, *dest_ptr;
  101.   char ch;
  102.  
  103.  
  104.   for (src_ptr=src, dest_ptr=dest; *src_ptr;  src_ptr++, dest_ptr++)
  105.     {
  106.       if(*src_ptr != '\\')
  107.         *dest_ptr = *src_ptr;
  108.       else
  109.         {
  110.           ch = *(++src_ptr);
  111.           if((ch>='0') && (ch<='3')) /* assume next 2 chars are octal too */
  112.             {
  113.               *dest_ptr = ((ch & 07) << 6);
  114.               *dest_ptr |= ((*(++src_ptr)&07)<<3);
  115.               *dest_ptr |= *(++src_ptr)&07;
  116.             }
  117.           else
  118.             {
  119.               switch(ch)
  120.                 {
  121.                 case 'a' : *dest_ptr = '\a'; break;
  122.                 case 'b' : *dest_ptr = '\b'; break;
  123.                 case 't' : *dest_ptr = '\t'; break;
  124.                 case 'r' : *dest_ptr = '\r'; break;
  125.                 case 'n' : *dest_ptr = '\n'; break;
  126.                 case 'v' : *dest_ptr = '\v'; break;
  127.                 case 'f' : *dest_ptr = '\f'; break;
  128.                 default  : *dest_ptr = *src_ptr;
  129.                 }
  130.             }
  131.         }
  132.     }
  133.   *dest_ptr = 0;
  134.  
  135.   return dest;
  136. }
  137.  
  138.  
  139. #define CHECK_BUFFER_SIZE(ptr) \
  140.         if ((ptr) >= buffer_size-1) {\
  141.         buffer_size += BUFFER_SIZE_INCREMENT;\
  142.         buffer = wrealloc(buffer, buffer_size);\
  143.          }
  144.  
  145.  
  146. #define ISSTRINGABLE(c) (isalnum(c) || (c)=='.' || (c)=='_' || (c)=='/' \
  147.         || (c)=='+')
  148.  
  149.  
  150.  
  151. #define COMPLAIN(msg)  wwarning(_("syntax error in %s, line %i:%s"), \
  152.                 file_name, line_number, msg)
  153.  
  154.  
  155. static proplist_t
  156. get_qstring(FILE *f)
  157. {
  158.     int c;
  159.     int ptr = 0;
  160.     int escaping = 0;
  161.     int ok = 1;
  162.  
  163.     while (1) {
  164.     c = get_char(f);
  165.     if (!escaping) {
  166.         if (c=='\\') {
  167.         escaping = 1;
  168.         continue;
  169.         }
  170.         if (c=='"')
  171.         break;
  172.     } else {
  173.         CHECK_BUFFER_SIZE(ptr);
  174.         buffer[ptr++] = '\\';        
  175.         escaping = 0;
  176.     }
  177.     if (c==EOF) {
  178.         ptr--;
  179.         ok = 0;
  180.         COMPLAIN(_("unterminated string"));
  181.         break;
  182.     } else {
  183.         CHECK_BUFFER_SIZE(ptr);
  184.         buffer[ptr++] = c;
  185.     }
  186.     }
  187.     
  188.     buffer[ptr] = 0;
  189.  
  190.     if (!ok)
  191.     return NULL;
  192.     else {
  193.     char *tmp = unescapestr(buffer);
  194.     proplist_t pl = PLMakeString(tmp);
  195.     free(tmp);
  196.     return pl;
  197.     }
  198. }
  199.  
  200.  
  201.  
  202. static proplist_t
  203. get_string(FILE *f)
  204. {
  205.     int c;
  206.     int ptr = 0;
  207.     
  208.     while (1) {
  209.     c = get_char(f);
  210.     if (ISSTRINGABLE(c)) {
  211.         CHECK_BUFFER_SIZE(ptr);
  212.         buffer[ptr++] = c;
  213.     } else {
  214.         if (c!=EOF) {
  215.         ungetc(c, f);
  216.         }
  217.         break;
  218.     }
  219.     }
  220.     buffer[ptr] = 0;
  221.  
  222.     if (ptr==0)
  223.     return NULL;
  224.     else {
  225.     char *tmp = unescapestr(buffer);
  226.     proplist_t pl = PLMakeString(tmp);
  227.     free(tmp);
  228.     return pl;
  229.     }
  230. }
  231.  
  232.  
  233.  
  234.  
  235. static proplist_t
  236. get_array(FILE *f)
  237. {
  238.     int c;
  239.     int ok=1, first=1;
  240.     proplist_t list, obj;
  241.     
  242.     list = PLMakeArrayFromElements(NULL);
  243.     
  244.     while (1) {
  245.     c = get_non_space_char(f);
  246.     if (c==EOF) {
  247.         COMPLAIN(_("unterminated array"));
  248.         ok = 0;
  249.         break;
  250.     } else if (c==')') {
  251.         break;
  252.     } else if (c==',') {
  253.         /* continue normally */
  254.     } else {
  255.         if (!first) {
  256.         COMPLAIN(_("missing , in array or unterminated array"));
  257.         ok = 0;
  258.         break;
  259.         } else {
  260.         ungetc(c, f);
  261.         }
  262.     }
  263.     first = 0;
  264.     /* get the data */
  265.     obj = get_object(f);
  266.     if (!obj) {
  267.         COMPLAIN(_("could not get array element"));
  268.         ok = 0;
  269.         break;
  270.     }
  271.     list = PLAppendArrayElement(list, obj);
  272.     PLRelease(obj);
  273.     }
  274.     
  275.     if (ok)
  276.     return list;
  277.     else {
  278.     PLRelease(list);
  279.     return NULL;
  280.     }
  281. }
  282.  
  283.  
  284. static proplist_t
  285. get_dictionary(FILE *f)
  286. {
  287.     int c;
  288.     int ok = 1;
  289.     proplist_t dict, key, value;
  290.     
  291.     dict = PLMakeDictionaryFromEntries(NULL, NULL);
  292.  
  293.     while (1) {
  294.     c = get_non_space_char(f);
  295.     
  296.     if (c==EOF) {
  297.         COMPLAIN(_("unterminated dictionary"));
  298.         ok = 0;
  299.         break;
  300.     } else if (c=='}') {
  301.         break;
  302.     }
  303.     
  304.     /* get the entry */
  305.     
  306.     /* get key */
  307.     DPUT("getting dict key");
  308.     if (c=='"')
  309.         key = get_qstring(f);
  310.     else if (ISSTRINGABLE(c)) {
  311.         ungetc(c, f);
  312.         key = get_string(f);
  313.     } else {
  314.         if (c=='=')
  315.         COMPLAIN(_("missing dictionary key"));
  316.         else
  317.         COMPLAIN(_("missing dictionary entry key or unterminated dictionary"));
  318.         ok = 0;
  319.         break;
  320.     }
  321.     
  322.     if (!key) {
  323.         COMPLAIN(_("error parsing dictionary key"));
  324.         ok = 0;
  325.         break;
  326.     }
  327.     DPUT("getting =");
  328.     /* get = */
  329.     c = get_non_space_char(f);
  330.     if (c!='=') {
  331.         PLRelease(key);
  332.         COMPLAIN(_("missing = in dictionary entry"));
  333.         ok = 0;
  334.         break;
  335.     }
  336.     DPUT("getting dict entry data");
  337.     /* get data */
  338.     value = get_object(f);
  339.     if (!value) {
  340.         /*
  341.         COMPLAIN(_("error parsing dictionary entry value"));
  342.          */
  343.         ok = 0;
  344.         PLRelease(key);
  345.         break;
  346.     }
  347.     DPUT("getting ;");
  348.     /* get ; */
  349.     c = get_non_space_char(f);
  350.     if (c!=';') {
  351.         COMPLAIN(_("missing ; in dictionary entry"));
  352.         ok = 0;
  353.         PLRelease(key);
  354.         PLRelease(value);
  355.         break;
  356.     }
  357.     dict = PLInsertDictionaryEntry(dict, key, value);
  358.     PLRelease(key);
  359.     PLRelease(value);
  360.     }
  361.  
  362.     if (!ok) {
  363.     PLRelease(dict);
  364.     return NULL;
  365.     } else {
  366.     return dict;
  367.     }
  368. }
  369.  
  370.  
  371. static proplist_t
  372. get_data(FILE *f)
  373. {
  374.  
  375.     
  376.     COMPLAIN("the data datatype is not yet implemented");
  377.     
  378.     return NULL;
  379. }
  380.  
  381.  
  382.  
  383.  
  384.  
  385. static proplist_t
  386. get_object(FILE *f)
  387. {
  388.     int c;
  389.     proplist_t pl;
  390.     
  391.     c = get_non_space_char(f);
  392.     
  393.     switch (c) {
  394.     /* END OF FILE */
  395.      case EOF:
  396.     DPUT("EOF");
  397.     pl = NULL;
  398.     break;
  399.     
  400.     /* dictionary */
  401.      case '{':
  402.     DPUT("getting dictionary");
  403.     pl = get_dictionary(f);
  404.     break;
  405.     
  406.     /* array */
  407.      case '(':
  408.     DPUT("getting arrray");
  409.     pl = get_array(f);
  410.     break;
  411.     
  412.     /* data */
  413.      case '<':
  414.     DPUT("getting data");
  415.     pl = get_data(f);
  416.     break;
  417.  
  418.     /* quoted string */
  419.      case '"':
  420.     DPUT("getting qstring");
  421.     pl = get_qstring(f);
  422.     break;
  423.  
  424.     /* string */
  425.      default:
  426.     if (ISSTRINGABLE(c)) {
  427.         DPUT("getting string");
  428.         /* put back */
  429.         ungetc(c, f);
  430.         pl = get_string(f);
  431.     } else {
  432.         COMPLAIN(_("was expecting a string, dictionary, data or array. If it's a string, try enclosing it with \"."));
  433.         if (c=='#' || c=='/') {
  434.         wwarning(_("Comments are not allowed inside WindowMaker owned domain files."));
  435.         }
  436.         pl = NULL;
  437.     }
  438.     break;
  439.     }
  440.  
  441.     return pl;
  442. }
  443.  
  444.  
  445. proplist_t 
  446. ReadProplistFromFile(char *file)
  447. {
  448.     FILE *f;
  449.     proplist_t pl = NULL;
  450.     
  451.     f = fopen(file, "r");
  452.     if (!f) {
  453.     wsyserror(_("could not open domain file %s"), file);
  454.     return NULL;
  455.     }
  456.  
  457.     file_name = file;
  458.     line_number = 1;
  459.     buffer_size = INITIAL_BUFFER_SIZE;
  460.     buffer = wmalloc(buffer_size);
  461.  
  462.     pl = get_object(f);
  463.  
  464.     /* check for illegal characters after EOF */
  465.     if (get_non_space_char(f)!=EOF && pl) {
  466.     COMPLAIN(_("extra data after end of file"));
  467.     /* 
  468.      * We can't just ignore garbage after the file because the "garbage"
  469.      * could be the data and the real garbage be in the beginning of
  470.      * the file (wich is now, inside pl)
  471.      */
  472.     PLRelease(pl);
  473.     pl = NULL;
  474.     }
  475.  
  476.     free(buffer);
  477.  
  478.     fclose(f);
  479.  
  480.     if (pl) {
  481.     proplist_t fpl;
  482.  
  483.     fpl = PLMakeString(file);
  484.     PLSetFilename(pl, fpl);
  485.     PLRelease(fpl);
  486.     }
  487.     return pl;
  488. }
  489.  
  490.  
  491.  
  492.